import math
import os

from odoo import models, fields, api, _
from odoo.exceptions import UserError, ValidationError


class SaleOrderLine(models.Model):
    _inherit = "sale.order.line"

    ship_instructions_id = fields.Many2one('ship.instructions', string='Ship Instructions', ondelete='set null')
    ship_instructions_lines = fields.One2many('ship.instructions.line', 'sale_order_line_id',
                                              string="Instructions Line")
    s_customer_item_code = fields.Many2one('customer.item.code')
    pn = fields.Char(string="PN", related="s_customer_item_code.code", store=True)
    pn_rev = fields.Char(string="PN REV", related="s_customer_item_code.version", store=True)
    pn_des = fields.Char(related='s_customer_item_code.customer_item_desc')
    po = fields.Char(string="PO", store=True)
    qty_available = fields.Float(string="Inventory Qty", compute="_compute_qf", digits='Product Unit of Measure')
    free_qty = fields.Float(string="Available Qty", compute="_compute_qf", digits='Product Unit of Measure')
    origin_price = fields.Float(string="Origin Price")
    indicated_qty = fields.Integer(string="Indicated Qty", compute="_compute_indicated_qty")
    po_line = fields.Char(string="PO Line")
    price_unit = fields.Float(
        string="Unit Price",
        digits='Product Price', compute=None,
        store=True, readonly=False, required=True, precompute=False)

    @api.depends('ship_instructions_lines.delivery_qty')
    def _compute_indicated_qty(self):
        for record in self:
            total_delivery_qty = sum(record.ship_instructions_lines.mapped('delivery_qty'))
            record.indicated_qty = total_delivery_qty

    def _compute_qf(self):
        for re in self:
            if re.product_id.product_variant_id:
                re.qty_available = re.product_id.product_variant_id.qty_available
                re.free_qty = re.product_id.product_variant_id.free_qty
            else:
                re.qty_available = 0
                re.free_qty = 0

    # @api.depends('product_template_id')
    # @api.onchange('product_template_id')
    # def _compute_customer_item_code(self):
    #     for line in self:
    #         # 通过过滤相关记录来获取PN和PN REV
    #         customer_item_code = line.product_template_id.customer_item_code_ids.filtered(
    #             lambda x: x.customer_id == line.order_id.partner_id and x.product_id == line.product_template_id
    #         )
    #         if customer_item_code:
    #             sorted_customer_item_code = customer_item_code.sorted(key=lambda r: r.sequence)
    #             line.pn = sorted_customer_item_code[0].code
    #             line.pn_rev = sorted_customer_item_code[0].version
    #         else:
    #             line.pn = False
    #             line.pn_rev = False
    # 重新原生计算方法，去掉产品过滤
    def _get_outgoing_incoming_moves(self):
        outgoing_moves = self.env['stock.move']
        incoming_moves = self.env['stock.move']

        moves = self.move_ids.filtered(lambda r: r.state != 'cancel' and not r.scrapped)  # 只改动此位置，去掉产品过滤
        if self._context.get('accrual_entry_date'):
            moves = moves.filtered(lambda r: fields.Date.context_today(r, r.date) <= self._context['accrual_entry_date'])

        for move in moves:
            if move.location_dest_id.usage == "customer":
                if not move.origin_returned_move_id or (move.origin_returned_move_id and move.to_refund):
                    outgoing_moves |= move
            elif move.location_dest_id.usage != "customer" and move.to_refund:
                incoming_moves |= move

        return outgoing_moves, incoming_moves


SALE_ORDER_STATE = [
    ('draft', "Sales Order"),
    ('sent', "Quotation Sent"),
    ('sale', "Production Order"),
    ('cancel', "Cancelled"),
]


# 销售类
class SaleOrder(models.Model):
    _inherit = 'sale.order'

    sb_workflow_template_id = fields.Many2one('sb.workflow.template', string="Approval Workflow Template",
                                              domain="[('sb_workflow_template_item_ids', '!=', False),"
                                                     "('workflow_type', 'in', ['other', 'sale'])]")
    partner_shipping_id = fields.Many2one(
        domain="[('parent_id', '=', partner_id), ('type', '=', 'delivery'),('company_id','in',(False,company_id))]",
        ondelete="restrict")
    partner_id = fields.Many2one(tracking=True, ondelete="restrict", string="Customer",
                                 domain="[('is_virtual_customer','!=','True'),('supplier_rank','<=',0),('company_id','in',(False,company_id)),('code','!=',False)]")
    jove_code = fields.Char(related="partner_id.s_regular_code")
    sb_workflow_id = fields.Many2one('sb.workflow', string="Current Approval Workflow", copy=False)
    sb_workflow_state = fields.Selection(related="sb_workflow_id.state", readonly=True, string="Approval Status",
                                         store=True)
    sb_workflow_item_ids = fields.One2many(related="sb_workflow_id.sb_workflow_item_ids", string="Approval Items")
    sb_workflow_attachments_ids = fields.One2many(related="sb_workflow_id.sb_workflow_attachments_ids",
                                                  string="Approval Attachments")

    sb_workflow_ids = fields.One2many('sb.workflow', 'sale_order_id', string="Approval Workflows")
    sb_workflow_ids_sum = fields.Integer(compute="_compute_sb_workflow_ids_sum", store=True)
    first_line = fields.Many2one('sale.order.line', string="First Line", compute="_compute_first_line",
                                 store=True, readonly=True, copy=False)
    product_id = fields.Many2one('product.template', string='MPN', related="first_line.product_template_id",
                                 store=True)
    unit_price = fields.Float(string='Unit Price', related="first_line.price_unit", digits='Product Price')
    planned_receiving_date = fields.Datetime(string='Factory DD')
    final_delivery_date = fields.Date(string='Final DD')
    commitment_date = fields.Datetime(tracking=True, string='Customer DD')
    pn = fields.Char(string="PN", related="first_line.pn", store=True)
    pn_rev = fields.Char(string="PN REV", related="first_line.pn_rev", store=True)
    pn_des = fields.Char(string="PN Description", related="first_line.pn_des", store=True)
    indicate_state = fields.Selection([
        ('unconfirmed', 'UnConfirm'),
        ('part_confirmed', 'Part Confirm'),
        ('confirmed', 'Confirmed')
    ], default='unconfirmed', copy=False, tracking=True, store=True, compute="_compute_indicate_state",
        company_sudo=True)

    qty_available = fields.Float(string="Inventory Qty", compute="_compute_qf", digits='Product Unit of Measure')
    free_qty = fields.Float(string="Available Qty", compute="_compute_qf", digits='Product Unit of Measure')
    special_order_type = fields.Selection([
        ('eq_only', 'EQ only'),
        ('free_cost', 'Free cost'),
        ('wb', 'WB')
    ], string="Special Order Type", tracking=True)
    qty = fields.Integer(string="QTY", compute="_compute_qty", store=True)
    qty_shipped = fields.Integer(string="QTY Shipped", compute="_compute_qty", store=True)
    po = fields.Char(string="PO", tracking=True)
    team_id = fields.Many2one(related='user_id.sale_team_id', string='Sales Team', store=True)
    order_type = fields.Selection([
        ('new', 'NEW'),
        ('repeat', 'REPEAT'),
        ('change', 'CHANGE')
    ], string="Order Type", default=lambda self: self.env.context.get('order_type', 'new'))
    state = fields.Selection(SALE_ORDER_STATE, string="State", readonly=True, copy=False, tracking=True,
                             default='draft')
    end_po = fields.Char(string="End PO")
    end_pn = fields.Char(string="End PN")
    end_pn_rev = fields.Char(string="End PN REV")
    sale_workflow_state = fields.Char(string="Approval", compute="_compute_approve_state", store=True)
    s_picking_ids = fields.Many2many('stock.picking', compute="_compute_s_picking_ids", string="Picking IDs")
    s_ship_instructions_ids = fields.Many2many('ship.instructions', compute="_compute_s_ship_instructions_ids",
                                               string="Ship Instructions IDs")
    instructed_qty = fields.Integer(string="Instructed Qty", compute="_compute_instructed_qty")
    instructed_done = fields.Boolean(string="Instructed Done", compute="_compute_instructed_done", compute_sudo=True)
    s_nre = fields.Float(string="NRE", compute="_compute_s_nre", store=True)
    s_ext = fields.Float(string="Additional Charge", compute="_compute_s_nre", store=True)
    delivery_status = fields.Selection([
        ('pending', 'Not Delivered'),
        ('started', 'Started'),
        ('cancel', 'Cancel'),
        ('partial', 'Partially Delivered'),
        ('full', 'Fully Delivered'),
    ], string='Delivery Status', compute='_compute_delivery_status', store=True)

    s_document_ids = fields.One2many('documents.document', 'res_id', string='Documents',
                                     domain="[('res_model', '=', 'sale.order'), ('res_id', '=', id)]")
    s_amount_total_usd = fields.Monetary(string="($)Total Amount", currency_field='s_currency_id_usd',
                                         compute_sudo=True, store=True, compute='_compute_amount_total_usd')
    s_currency_id_usd = fields.Many2one('res.currency', default=lambda self: self.env.ref('base.USD'), readonly=True, store=True)
    s_project_name = fields.Char('Project Name', related='opportunity_id.project_name')

    @api.model
    def write(self, vals):
        if 'po' in vals and vals['po'] != '':
            for line in self.order_line:
                line.write({'po': vals['po']})
        return super(SaleOrder, self).write(vals)

    @api.depends('amount_total', 'currency_id', 'create_date', 'order_line.product_uom_qty', 'order_line.price_unit')
    def _compute_amount_total_usd(self):
        usd = self.env.ref('base.USD')
        for order in self:
            if order.currency_id == usd:
                order.s_amount_total_usd = order.amount_total
            else:
                rate = order.currency_id._get_conversion_rate(
                    order.currency_id, usd, order.company_id, order.create_date)
                order.s_amount_total_usd = order.amount_total * rate

    def action_view_documents(self):
        self.ensure_one()
        return {
            'name': 'Documents',
            'type': 'ir.actions.act_window',
            'res_model': 'documents.document',
            'view_mode': 'kanban,tree,form',
            'domain': [
                ('res_model', '=', 'sale.order'),
                ('res_id', '=', self.id),
            ],
            'context': {
                'default_res_model': 'sale.order',
                'default_res_id': self.id,
                'create': False,
                'searchpanel_default_folder_id': self.env.ref('documents.documents_marketing_folder').id,
            },
            'target': 'current',
        }

    @api.depends('order_line.product_id')
    def _compute_s_nre(self):
        # 预取产品模板 ID，避免循环内反复 search
        nre_tmpl = self.env.ref('sb_sale.nre_server_product', raise_if_not_found=False)
        ext_tmpl = self.env.ref('sb_sale.extra_charge_server_product', raise_if_not_found=False)

        for order in self:
            order.s_nre = 0
            order.s_ext = 0
            for line in order.order_line:
                if nre_tmpl and line.product_id.product_tmpl_id == nre_tmpl:
                    order.s_nre = line.price_unit
                # 再判断 NRE-Engineering
                if ext_tmpl and line.product_id.product_tmpl_id == ext_tmpl:
                    order.s_ext = line.price_unit

    @api.depends(
        'order_line.ship_instructions_lines.delivery_qty',
        'order_line.ship_instructions_lines.ship_instructions_id.state',
        'first_line.product_uom_qty'
    )
    def _compute_indicate_state(self):
        """
        根據銷售訂單中嘅出貨指令，計算指示狀態。
        狀態包括：未確認、部分確認、已確認。
        """
        for rec in self:
            total_required = rec.first_line.product_uom_qty if rec.first_line else 0.0
            total_instructed = 0.0
            for line in rec.order_line:
                valid_instructions = line.ship_instructions_lines.filtered(
                    lambda x: x.ship_instructions_id.state not in ['readying', 'cancel']
                )
                total_instructed += sum(valid_instructions.mapped('delivery_qty'))

            if total_required == 0 or total_instructed == 0:
                rec.indicate_state = 'unconfirmed'
            elif total_required > total_instructed:
                rec.indicate_state = 'part_confirmed'
            else:
                rec.indicate_state = 'confirmed'

    @api.depends('order_line', 'order_line.move_ids', 'order_line.move_ids.state', 'write_date')
    def _compute_delivery_status(self):
        for order in self:
            # 获取所有非服务类产品的订单行
            non_service_lines = order.order_line.filtered(lambda line: line.product_id.type != 'service')
            moves = non_service_lines.mapped('move_ids')

            if not moves:
                order.delivery_status = False
            elif all(move.state == 'cancel' for move in moves):
                order.delivery_status = 'cancel'
            else:
                # 检查是否有任何 move 的状态为 'done'
                done_moves = moves.filtered(lambda move: move.state == 'done')
                if done_moves:
                    # 如果有 'done' 状态的 move，检查订单数量是否等于出货数量
                    if all(line.product_uom_qty == line.qty_delivered for line in non_service_lines):
                        order.delivery_status = 'full'
                    else:
                        order.delivery_status = 'partial'
                else:
                    # 如果没有 'done' 状态的 move，但有其他状态的 move，设置为 'started'
                    order.delivery_status = 'started'

    @api.depends('sb_workflow_state', 'sb_workflow_item_ids.state', 'sb_workflow_template_id')
    def _compute_approve_state(self):
        for re in self:
            if re.state == 'cancel':
                re.sale_workflow_state = 'Cancel'
            else:
                if not re.sb_workflow_template_id or not re.sb_workflow_state:
                    re.sale_workflow_state = 'Not Submitted'
                else:
                    if re.sb_workflow_state == 'approval':
                        # 找到状态为 'approval' 的 sb_workflow_item_ids 行
                        approval_item = re.sb_workflow_item_ids.filtered(lambda x: x.state == 'approval')
                        if approval_item:
                            # 如果存在多条状态为 'approval' 的记录，取第一条的 name
                            re.sale_workflow_state = approval_item[0].name
                        else:
                            re.sale_workflow_state = 'Not Approved'
                    else:
                        re.sale_workflow_state = re.sb_workflow_state.capitalize()

    @api.depends('order_line.ship_instructions_lines')
    def _compute_s_ship_instructions_ids(self):
        for rec in self:
            ship_instructions = rec.order_line.mapped('ship_instructions_lines.ship_instructions_id')
            rec.s_ship_instructions_ids = ship_instructions

    @api.depends('order_line.ship_instructions_lines.delivery_qty',
                 'order_line.ship_instructions_lines.ship_instructions_id.state')
    def _compute_instructed_qty(self):
        for rec in self:
            lines = rec.order_line.mapped('ship_instructions_lines')
            lines_done = lines.filtered(lambda l: l.ship_instructions_id.state not in ['done', 'cancel'])
            rec.instructed_qty = sum(lines_done.mapped('delivery_qty'))

    @api.depends('qty', 'instructed_qty')
    def _compute_instructed_done(self):
        for re in self:
            re.instructed_done = False
            if re.qty == re.instructed_qty:
                re.instructed_done = True

    def action_view_s_ship_instructions(self):
        self.ensure_one()
        ship_instructions = self.s_ship_instructions_ids
        action = {
            'type': 'ir.actions.act_window',
            'res_model': 'ship.instructions',
            'name': 'Ship Instructions',
            'target': 'current',
        }
        if len(ship_instructions) == 1:
            action['view_mode'] = 'form'
            action['res_id'] = ship_instructions.id
        else:
            action['view_mode'] = 'tree,form'
            action['domain'] = [('id', 'in', ship_instructions.ids)]
        return action

    @api.depends('order_line.move_ids')
    def _compute_s_picking_ids(self):
        for rec in self:
            # 从所有 order_line 的 move_ids 中提取 picking_id
            pickings = rec.order_line.mapped('move_ids.picking_id')
            rec.s_picking_ids = pickings

    def action_view_s_delivery(self):
        '''
        This function returns an action that display existing delivery orders
        of given sales order. It can either be a in a list or in a form
        view, if there is only one delivery order to show.
        '''
        # pickings = self.s_picking_ids.filtered(lambda p: p.state != 'cancel')
        pickings = self.s_picking_ids
        action = self.env["ir.actions.actions"]._for_xml_id("stock.action_picking_tree_all")
        if len(pickings) > 1:
            action['domain'] = [('id', 'in', pickings.ids)]
        elif pickings:
            form_view = [(self.env.ref('stock.view_picking_form').id, 'form')]
            if 'views' in action:
                action['views'] = form_view + [(state, view) for state, view in action['views'] if view != 'form']
            else:
                action['views'] = form_view
            action['res_id'] = pickings[0].id
        picking_id = pickings.filtered(lambda l: l.picking_type_id.code == 'outgoing')
        if picking_id:
            picking_id = picking_id[0]
        else:
            picking_id = pickings[0] if pickings else None
        if picking_id:
            action['context'] = dict(
                self._context,
                default_partner_id=self.partner_id.id,
                default_picking_type_id=picking_id.picking_type_id.id,
                default_origin=self.name,
                default_group_id=picking_id.group_id.id
            )

        return action

    @api.depends('order_line', 'order_line.product_uom_qty', 'order_line.qty_delivered', 'delivery_status')
    def _compute_qty(self):
        for re in self:
            # 过滤掉类型为 'service' 的产品
            non_service_lines = re.order_line.filtered(lambda line: line.product_id.type != 'service')
            re.qty = sum(non_service_lines.mapped('product_uom_qty'))
            re.qty_shipped = sum(non_service_lines.mapped('qty_delivered'))

    def _compute_qf(self):
        for re in self:
            if re.product_id.product_variant_id:
                re.qty_available = re.product_id.product_variant_id.qty_available
                re.free_qty = re.product_id.product_variant_id.free_qty
            else:
                re.qty_available = 0
                re.free_qty = 0

    @api.constrains('sb_workflow_state')
    def _check_sb_workflow_state(self):
        for record in self:
            if record.sb_workflow_state == 'approve' and record.state in ('draft', 'sent'):  # 审批通过自动确认订单
                record.action_confirm()
                record.sudo().action_lock()

    def action_draft_cancel(self):
        for order in self:
            if order.state != 'draft':
                raise UserError(_("Only draft orders can be cancelled."))
            else:
                if order.order_type == 'new':
                    order.write({
                        'state': 'cancel',
                        'status': 'cancelled',
                    })
                    if order.first_line.s_customer_item_code:
                        order.first_line.s_customer_item_code.unlink()
                else:
                    order.write({
                        'state': 'cancel',
                        'status': 'cancelled',
                    })
        message_text = _("The order has been cancelled. At the same time, I hope you will double-check your next order.")
        return {
            'type': 'ir.actions.client',
            'tag': 'display_notification',
            'params': {
                'title': 'Success',
                'type': 'success',
                'message': message_text,
                'sticky': False,
                'next': {'type': 'ir.actions.act_window_close'},  # 關閉當前窗口
            }
        }

    def unlink(self):
        for record in self:
            if record.sb_workflow_item_ids:
                raise ValidationError(
                    _("You can't delete an order after it's been submitted for approval, maybe you want is cancel it."))
        return super(SaleOrder, self).unlink()

    # @api.depends('product_id', 'partner_id')
    # def _compute_pn(self):
    #     for record in self:
    #         for p in record.product_id.customer_item_code_ids:
    #             if p.customer_id.id == record.partner_id.id:
    #                 record.pn = p.code
    #                 record.pn_rev = p.version

    @api.depends('order_line')
    def _compute_first_line(self):
        for rec in self:
            if rec.order_line:
                rec.first_line = rec.order_line[0]

    def new_product(self):
        return {
            'name': 'New Product',
            'type': 'ir.actions.act_window',
            'res_model': 'product.template',
            'view_mode': 'form',
            'target': 'new',
        }

    # 确认销售单-生成审批流
    def create_workflow(self):
        if not self.s_document_ids and self.order_type == 'new':
            raise ValidationError(_('It seems that you forgot to upload the attachment.😱 Tips: You can upload the attachment by clicking the "Add File" button.'))
        if self.sb_workflow_template_id:
            if len(self.sb_workflow_ids) > 0:
                workflow_sum = len(self.sb_workflow_ids) + 1
            else:
                workflow_sum = 1
            # 创建审批流
            new_wf_id = self.env['sb.workflow'].sudo().create({
                'name': self.name + _('-Approval Flow') + '-' + str(workflow_sum),
                'approval_time': fields.Datetime.now(),
                'workflow_type': 'sale',
                'sale_order_id': self.id,
                'res_id': self.id,
                'res_model': self._name,
            })
            self.sb_workflow_id = new_wf_id.id
            # 根据模板生成审批项
            item_audit_levels = []
            for item in self.sb_workflow_template_id.sb_workflow_template_item_ids:
                new_item = self.env['sb.workflow.item'].sudo().create({
                    'name': item.name,
                    'user_group_ids': item.user_group_ids.ids,
                    'audit_level': item.audit_level,
                    'sb_workflow_id': new_wf_id.id,
                    'state': 'wait_forward',
                    'is_plan': item.is_plan,
                    'is_jmi_upload': item.is_jmi_upload,
                    'is_engineering': item.is_engineering
                })
                # 收集生成的审核项的所有层级
                item_audit_levels.append(new_item.audit_level)
            # 去重排序
            item_audit_levels = list(set(item_audit_levels))
            item_audit_levels.sort()
            for n_item in new_wf_id.sb_workflow_item_ids:
                if n_item.audit_level == item_audit_levels[0]:
                    n_item.state = 'approval'
        else:
            raise ValidationError(_('Please select an approval template.💦'))

    # 拦截未审批的报价单确认
    def action_confirm(self):
        if not self.sb_workflow_id:
            raise ValidationError(_('The order has not been approved. Please submit for approval first.'))
        if self.sb_workflow_state != 'approve':
            raise ValidationError(_('Order Approval Not Passed!'))
        if self.special_order_type == 'eq_only':
            raise ValidationError(_("Wait Wait!!! This MO type is still on 'EQ only'!"))
        if self.product_id.s_disable_down_card:  # down card是谁想出来的 (place lot card)
            raise ValidationError(_("Wait Wait!!! This %s prohibits creation of manufacturing orders'!") % self.product_id.name)

        pcs_in_set = 1
        if self.product_id:
            pcs_in_set = self.product_id.uom_value_ids.filtered(lambda x: x.uom_id.name == "SET").uom_value

        if pcs_in_set and self.first_line.product_uom_qty % pcs_in_set != 0:
            sales = self.user_id.name if self.user_id else 'Market'
            raise ValidationError(_(
                f"The MO Order qty is not a multiple of the SET qty (%s). "
                f"Please contact %s to modify the quantity of MO"
            ) % (pcs_in_set, sales))

        for line in self.order_line:
            if not line.product_template_id.active:
                raise ValidationError(line.product_template_id.name +
                                      _('Not approved by the product, please approve first'))
        res = super(SaleOrder, self).action_confirm()
        for order in self:
            order.picking_ids.filtered(lambda p: p.state != 'done').unlink()
        return res

    # 拦截未审批的报价单邮件交互
    def action_quotation_send(self):
        if not self.sb_workflow_id:
            raise ValidationError(_('The order has not been approved. Please submit for approval first.'))
        if self.sb_workflow_state != 'approve':
            raise ValidationError(_('Order Approval Not Passed!'))
        for line in self.order_line:
            if not line.product_template_id.active:
                raise ValidationError(line.product_template_id.name +
                                      _('Not approved by the product, please approve first'))
        return super(SaleOrder, self).action_quotation_send()

    # 跳转审批流页面
    def action_workflow(self):
        return {
            'name': 'Approval Flow',
            'type': 'ir.actions.act_window',
            'res_model': 'sb.workflow',
            'view_mode': 'form',
            'res_id': self.sb_workflow_id.id,
            'target': 'current',
        }

    # 计算当前单据审批流数
    @api.depends('sb_workflow_ids')
    def _compute_sb_workflow_ids_sum(self):
        for item in self:
            if item.sb_workflow_ids:
                item.sb_workflow_ids_sum = len(item.sb_workflow_ids)
            else:
                item.sb_workflow_ids_sum = 0

    # 跳转当前单据审批流列表
    def action_view_workflow(self):
        return {
            'name': 'Approval Flow',
            'type': 'ir.actions.act_window',
            'res_model': 'sb.workflow',
            'view_mode': 'tree,form',
            'target': 'current',
            'domain': [('sale_order_id', '=', self.id)],
        }

    def action_open_document_upload_wizard(self):
        self.ensure_one()
        return {
            'type': 'ir.actions.act_window',
            'name': 'Upload Document',
            'res_model': 'document.upload.wizard',
            'view_mode': 'form',
            'target': 'new',
            'context': {
                'default_res_model': 'sale.order',
                'default_res_id': self.id,
                'default_folder_id': self.env.ref('documents.documents_marketing_folder').id,
                'default_partner_id': self.partner_id.id,
                'default_tag_id': self.with_context(lang='en_US').env['documents.tag'].search(
                    [('name', '=', 'Order Data')]).id if self.order_type == 'repeat' else
                self.with_context(lang='en_US').env['documents.tag'].search(
                    [('name', '=', 'Customer Document')]).id
            },
        }

    def create_shipping_instructions(self):
        records = self.env['sale.order'].browse(
            self._context.get('active_ids', []))
        reference_partner_id = records[0].partner_id.id
        reference_shipping_address = records[0].partner_shipping_id.id
        special_order_type = records[0].special_order_type
        for record in records:
            if record.indicate_state == 'confirmed' and record.delivery_status == 'full':
                raise UserError(_("What are you doing? This MO FG is completed shipment!😅"))
            if record.indicate_state == 'unconfirmed' and record.first_line.ship_instructions_lines.filtered(
                    lambda x: x.ship_instructions_id.state == 'readying'):
                raise UserError(
                    _(f"There have an another unconfirmed shipping instruction, please confirm or delete it %s.") % record.first_line.ship_instructions_lines.filtered(
                        lambda x: x.ship_instructions_id.state == 'readying').ship_instructions_id.name)
            if not record.state in ['sale']:
                raise UserError(_("This MO state is not done.😫"))
            if record.partner_id.id != reference_partner_id:
                raise UserError(_("Please select same customer!!!🙃"))
            if not record.final_delivery_date:
                raise UserError(_("Please select a Final date first!!!😅"))
            if record.special_order_type != special_order_type:
                if special_order_type == 'free_cost' or record.special_order_type == 'free_cost':
                    raise UserError(_("You cannot mix different types of orders with 'Free Cost' type orders. Please separate them.⚠"))

        ship_instructions_id = self.env['ship.instructions'].create({
            'name': self.env['ir.sequence'].next_by_code('ship.instructions'),
            'instructor': self.env.user.id,
            'partner_id': reference_partner_id,
            'contacts': records[0].partner_id.contact_child_ids[0].id if records[
                0].partner_id.contact_child_ids else False,
            'shipping_id': reference_shipping_address,
            'incoterm': records[0].incoterm.id,
            'free_cost': False if special_order_type != 'free_cost' else True
        })
        line_vals = []
        for record in records:
            for sol in record.order_line:
                if sol.product_template_id.detailed_type == 'product':
                    lines = sol.mapped('ship_instructions_lines')
                    lines_done = lines.filtered(lambda l: l.ship_instructions_id.state not in ['done', 'cancel'])
                    instructed_qty = sum(lines_done.mapped('delivery_qty'))
                    line_vals.append((0, 0, {
                        'sale_order_id': record.id,
                        'sale_order_line_id': sol.id,
                        'instructed_qty': instructed_qty,
                        'delivery_qty': sol.qty_to_deliver - instructed_qty
                    }))
        ship_instructions_id.line_ids = line_vals
        return {
            'name': 'Shipping Instruction',
            'type': 'ir.actions.act_window',
            'res_model': 'ship.instructions',
            'view_mode': 'form',
            'res_id': ship_instructions_id.id,
            'target': 'current',
        }

    def migrate_attachments(self):
        # 获取所有 sale.order 记录
        sale_orders = self.env['sale.order'].search([])
        for order in sale_orders:
            # 获取当前 sale.order 的所有附件
            attachments = self.env['ir.attachment'].search([
                ('res_model', '=', 'sale.order'),
                ('res_id', '=', order.id)
            ])

            for attachment in attachments:
                # 检查是否已经存在对应的 documents.document 记录
                existing_document = self.env['documents.document'].search([
                    ('attachment_id', '=', attachment.id)
                ])

                if not existing_document:
                    # 如果不存在，创建一个新的 documents.document 记录
                    file_extension = os.path.splitext(attachment.name)[1] if attachment.name else ''
                    new_filename = f"%s %s" % (order.name, file_extension)

                    self.env['documents.document'].create({
                        'name': new_filename,
                        'datas': attachment.datas,
                        'res_model': 'sale.order',
                        'res_id': order.id,
                        'partner_id': order.partner_id.id,
                        'folder_id': self.env.ref('documents.documents_marketing_folder').id,
                        'tag_ids': [(4, self.with_context(lang='en_US').env['documents.tag'].search(
                            [('name', '=', 'Order Data')]).id)],
                        'is_locked': True,
                        'lock_uid': 2,
                        'attachment_id': attachment.id
                    })
